package com.xuantu.learn.ssh.dao;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Projections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * User: felix
 * Date: 14-9-29
 * Time: 下午3:07
 */
@Component("commonDAO")
//@Transactional(propagation = Propagation.REQUIRED)
public class CommonDAO implements ICommonDAO {

    private static Logger LOGGER = LoggerFactory.getLogger(CommonDAO.class);

    @Autowired
    @Qualifier("sessionFactory")
    private SessionFactory sessionFactory;

    @Autowired
    @Qualifier("jdbcTemplate")
    private JdbcTemplate jdbcTemplate;

    public Session getSession() {
        return sessionFactory.getCurrentSession();
    }


    @Override
    public <T extends Serializable> T save(T model) {
        getSession().save(model);
        return model;
    }

    @Override
    public <T extends Serializable> void saveOrUpdate(T model) {
        getSession().saveOrUpdate(model);
    }

    @Override
    public <T extends Serializable> void update(T model) {
        getSession().update(model);
    }

    @Override
    public <T extends Serializable> void merge(T model) {
        getSession().merge(model);
    }

    @Override
    public <T extends Serializable, PK extends Serializable> void delete(Class<T> entityClass, PK id) {
        getSession().delete(get(entityClass, id));
    }

    @Override
    public <T extends Serializable> void deleteObject(T model) {
        getSession().delete(model);
    }

    @Override
    public <T extends Serializable, PK extends Serializable> T get(Class<T> entityClass, PK id) {
        return (T) getSession().get(entityClass, id);
    }

    @Override
    public <T extends Serializable> int count(Class<T> entityClass) {
        Criteria criteria = getSession().createCriteria(entityClass);
        criteria.setProjection(Projections.rowCount());
        return ((Long) criteria.uniqueResult()).intValue();
    }

    @Override
    public int count(String hql, Object... parameList) {
        Query query = getSession().createQuery(hql);
        setParameters(query, parameList);
        Long cnt = (Long)query.uniqueResult();
        return cnt.intValue();
    }

    @Override
    public <T extends Serializable> List<T> listAll(Class<T> entityClass) {
        Criteria criteria = getSession().createCriteria(entityClass);
        return criteria.list();
    }

    @Override
    public <T extends Serializable> List<T> listAll(Class<T> entityClass, int pageNo, int pageSize) {
        Criteria criteria = getSession().createCriteria(entityClass);
        criteria.setMaxResults(pageSize);
        criteria.setFirstResult(getPageStart(pageNo, pageSize));
        return criteria.list();
    }

    /**
     * 根据hql分页获取数据
     *
     * @param hql        Hql语句
     * @param pageNo     页数
     * @param pageSize   每页显示记录数
     * @param parameList 参数
     * @return
     */
    @Override
    public <T extends Serializable> List<T> list(String hql, int pageNo, int pageSize, Object... parameList) {
        Query query = getSession().createQuery(hql);
        setParameters(query, parameList);
        if (pageNo > -1 && pageSize > -1) {
            query.setMaxResults(pageSize);
            int start = getPageStart(pageNo, pageSize);
            if (start != 0) {
                query.setFirstResult(start);
            }
        }
        if (pageNo < 0) {
            query.setFirstResult(0);
        }
        List<T> results = query.list();
        return results;
    }

    /**
     * 根据sql查询数据
     *
     * @param sql
     * @param parameList
     * @return
     */
    @Override
    public List<Map<String, Object>> listBySql(String sql, Object... parameList) {
        LOGGER.debug(sql.replaceAll("\\?","{}") ,parameList);
        return jdbcTemplate.queryForList(sql, parameList);
    }

    /**
     * 根据sql操作
     *
     * @param sql
     * @param parameList
     */
    @Override
    public void executeSql(String sql, Object... parameList) {
        LOGGER.debug(sql.replaceAll("\\?","{}") ,parameList);
        jdbcTemplate.update(sql, parameList);
    }

    protected int getPageStart(int pageNumber, int pageSize) {
        return (pageNumber - 1) * pageSize;
    }

    protected void setParameters(Query query, Object[] paramlist) {
        if (paramlist != null) {
            for (int i = 0; i < paramlist.length; i++) {
                if(paramlist[i] instanceof Date) {
                    //TODO 难道这是bug 使用setParameter不行？？
                    query.setTimestamp(i, (Date)paramlist[i]);
                } else {
                    query.setParameter(i, paramlist[i]);
                }
            }
        }
    }



}
